﻿using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Threading.Tasks;
using Helpers.Extensions;

namespace Helpers
{
    public class ConnectionMultiplexerHelper
    {
        //private static object _locker = new Object();

        private static Dictionary<string, ConnectionMultiplexer> dictionary = new Dictionary<string, ConnectionMultiplexer>();
        public static ConnectionMultiplexer GetConnectionMultiplexer(string configuration)
        {
            if (configuration == null)
                throw new ArgumentNullException(nameof(configuration));
            if (!dictionary.ContainsKey(configuration) || !dictionary[configuration].IsConnected)
            {
                lock (configuration)
                {
                    if (!dictionary.ContainsKey(configuration) || !dictionary[configuration].IsConnected)
                    {
                        if (dictionary.ContainsKey(configuration))
                        {
                            dictionary[configuration].Dispose();
                            dictionary.Remove(configuration);
                        }
                        dictionary[configuration] = StackExchange.Redis.ConnectionMultiplexer.Connect(configuration);
                    }
                }
            }
            return dictionary[configuration];
        }
    }

    /// <summary>
    /// Redis操作
    /// </summary>
    public class RedisHelper
    {
        /// <summary>
        /// 数据库序号，默认是0号数据库
        /// </summary>
        private int DbNum { get; }
        public string CustomKey { get; set; }
        public static RedisHelper Instance = new RedisHelper();
        private string _config;
        ConnectionMultiplexer ConnectionMultiplexer => ConnectionMultiplexerHelper.GetConnectionMultiplexer(_config);

        public RedisHelper() : this("", 0, null)
        {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="prefixKey">前缀</param>
        /// <param name="dbNum">数据库</param>
        /// <param name="config">配置</param>
        public RedisHelper(string prefixKey, int dbNum, string config)
        {
            DbNum = dbNum;
            CustomKey = prefixKey;
            _config = config ?? "127.0.0.1:6379,abortConnect=false,ssl=false,allowAdmin=true,syncTimeout=30000,ConnectTimeout=10000";
        }

        #region String

        #region 同步方法

        /// <summary>
        /// 保存单个key value
        /// </summary>
        /// <param name="key">Redis Key</param>
        /// <param name="value">保存的值</param>
        /// <param name="expiry">过期时间</param>
        /// <returns></returns>
        public bool StringSet(string key, string value, TimeSpan? expiry = default(TimeSpan?))
        {
            key = MergeKey(key);
            return Do(db => db.StringSet(key, value, expiry));
        }

        /// <summary>
        /// 保存多个key value
        /// </summary>
        /// <param name="keyValues">键值对</param>
        /// <returns></returns>
        public bool StringSet(List<KeyValuePair<RedisKey, RedisValue>> keyValues)
        {
            List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =
                keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(MergeKey(p.Key), p.Value)).ToList();
            return Do(db => db.StringSet(newkeyValues.ToArray()));
        }

        /// <summary>
        /// 保存一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public bool StringSet<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))
        {
            key = MergeKey(key);
            string json = ConvertJson(obj);
            return Do(db => db.StringSet(key, json, expiry));
        }

        /// <summary>
        /// 获取单个key的值
        /// </summary>
        /// <param name="key">Redis Key</param>
        /// <returns></returns>
        public string StringGet(string key)
        {
            key = MergeKey(key);
            return Do(db => db.StringGet(key));
        }

        /// <summary>
        /// 获取多个Key
        /// </summary>
        /// <param name="listKey">Redis Key集合</param>
        /// <returns></returns>
        public RedisValue[] StringGet(List<string> listKey)
        {
            List<string> newKeys = listKey.Select(MergeKey).ToList();
            return Do(db => db.StringGet(ConvertRedisKeys(newKeys)));
        }

        /// <summary>
        /// 获取一个key的对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T StringGet<T>(string key) where T : class
        {
            key = MergeKey(key);
            return Do(db => ConvertToObj<T>(db.StringGet(key)));
        }

        /// <summary>
        /// 为数字增长val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">可以为负</param>
        /// <returns>增长后的值</returns>
        public double StringIncrement(string key, double val = 1)
        {
            key = MergeKey(key);
            return Do(db => db.StringIncrement(key, val));
        }

        /// <summary>
        /// 为数字减少val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">可以为负</param>
        /// <returns>减少后的值</returns>
        public double StringDecrement(string key, double val = 1)
        {
            key = MergeKey(key);
            return Do(db => db.StringDecrement(key, val));
        }

        #endregion 同步方法

        #region 异步方法

        /// <summary>
        /// 保存单个key value
        /// </summary>
        /// <param name="key">Redis Key</param>
        /// <param name="value">保存的值</param>
        /// <param name="expiry">过期时间</param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?))
        {
            key = MergeKey(key);
            return await Do(db => db.StringSetAsync(key, value, expiry));
        }

        /// <summary>
        /// 保存多个key value
        /// </summary>
        /// <param name="keyValues">键值对</param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync(List<KeyValuePair<RedisKey, RedisValue>> keyValues)
        {
            List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =
                keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(MergeKey(p.Key), p.Value)).ToList();
            return await Do(db => db.StringSetAsync(newkeyValues.ToArray()));
        }

        /// <summary>
        /// 保存一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public async Task<bool> StringSetAsync<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))
        {
            key = MergeKey(key);
            string json = ConvertJson(obj);
            return await Do(db => db.StringSetAsync(key, json, expiry));
        }

        /// <summary>
        /// 获取单个key的值
        /// </summary>
        /// <param name="key">Redis Key</param>
        /// <returns></returns>
        public async Task<string> StringGetAsync(string key)
        {
            key = MergeKey(key);
            return await Do(db => db.StringGetAsync(key));
        }

        /// <summary>
        /// 获取多个Key
        /// </summary>
        /// <param name="listKey">Redis Key集合</param>
        /// <returns></returns>
        public async Task<RedisValue[]> StringGetAsync(List<string> listKey)
        {
            List<string> newKeys = listKey.Select(MergeKey).ToList();
            return await Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys)));
        }

        /// <summary>
        /// 获取一个key的对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> StringGetAsync<T>(string key) where T : class
        {
            key = MergeKey(key);
            string result = await Do(db => db.StringGetAsync(key));
            return ConvertToObj<T>(result);
        }

        /// <summary>
        /// 为数字增长val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">可以为负</param>
        /// <returns>增长后的值</returns>
        public async Task<double> StringIncrementAsync(string key, double val = 1)
        {
            key = MergeKey(key);
            return await Do(db => db.StringIncrementAsync(key, val));
        }
        public async Task<long> StringIncrementAsync(string key, long val = 1)
        {
            key = MergeKey(key);
            return await Do(db => db.StringIncrementAsync(key, val));
        }

        /// <summary>
        /// 为数字减少val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val">可以为负</param>
        /// <returns>减少后的值</returns>
        public async Task<double> StringDecrementAsync(string key, double val = 1)
        {
            key = MergeKey(key);
            return await Do(db => db.StringDecrementAsync(key, val));
        }
        public async Task<long> StringDecrementAsync(string key, long val = 1)
        {
            key = MergeKey(key);
            return await Do(db => db.StringDecrementAsync(key, val));
        }

        #endregion 异步方法

        #endregion String

        #region Hash

        /// <summary>
        /// 判断某个数据是否已经被缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public Task<bool> HashExistsAsync(string key, string dataKey)
        {
            key = MergeKey(key);
            return Do(db => db.HashExistsAsync(key, dataKey));
        }

        public async Task<Dictionary<string, T>> HashGetAllAsync<T>(string key) where T : class
        {
            key = MergeKey(key);
            var value = await Do(db => db.HashGetAllAsync(key));
            return ConvetToDictionary<T>(value);

        }


        /// <summary>
        /// 存储数据到hash表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public Task<bool> HashSetAsync<T>(string key, string dataKey, T t)
        {
            key = MergeKey(key);
            return Do(db =>
            {
                string json = ConvertJson(t);
                return db.HashSetAsync(key, dataKey, json);
            });
        }

        /// <summary>
        /// 移除hash中的某值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public Task<bool> HashDeleteAsync(string key, string dataKey)
        {
            key = MergeKey(key);
            return Do(db => db.HashDeleteAsync(key, dataKey));
        }

        /// <summary>
        /// 移除hash中的多个值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dataKeys"></param>
        /// <returns></returns>
        public Task<long> HashDeleteAsync(string key, List<RedisValue> dataKeys)
        {
            key = MergeKey(key);
            //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"};
            return Do(db => db.HashDeleteAsync(key, dataKeys.ToArray()));
        }

        /// <summary>
        /// 从hash表获取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <returns></returns>
        public async Task<T> HashGetAsync<T>(string key, string dataKey) where T : class
        {
            key = MergeKey(key);
            string value = await Do(db => db.HashGetAsync(key, dataKey));
            return ConvertToObj<T>(value);
        }
        public T HashGet<T>(string key, string dataKey) where T : class
        {
            key = MergeKey(key);
            string value = Do(db => db.HashGet(key, dataKey));
            return ConvertToObj<T>(value);
        }

        /// <summary>
        /// 为数字增长val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <param name="val">可以为负</param>
        /// <returns>增长后的值</returns>
        public Task<double> HashIncrementAsync(string key, string dataKey, double val = 1)
        {
            key = MergeKey(key);
            return Do(db => db.HashIncrementAsync(key, dataKey, val));
        }

        /// <summary>
        /// 为数字减少val
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dataKey"></param>
        /// <param name="val">可以为负</param>
        /// <returns>减少后的值</returns>
        public Task<double> HashDecrementAsync(string key, string dataKey, double val = 1)
        {
            key = MergeKey(key);
            return Do(db => db.HashDecrementAsync(key, dataKey, val));
        }

        /// <summary>
        /// 获取hashkey所有Redis key
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> HashKeysAsync<T>(string key) where T : class
        {
            key = MergeKey(key);
            RedisValue[] values = await Do(db => db.HashKeysAsync(key));
            return ConvetToList<T>(values);
        }


        #endregion Hash

        #region List

        /// <summary>
        /// 移除指定ListId的内部List的值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public async Task<long> ListRemoveAsync<T>(string key, T value)
        {
            key = MergeKey(key);
            return await Do(db => db.ListRemoveAsync(key, ConvertJson(value)));
        }

        /// <summary>
        /// 限定list的长度
        /// </summary>
        public Task ListTrimAsync(RedisKey key, long start, long stop, CommandFlags flags = CommandFlags.None)
        {
            key = MergeKey(key);
            return Do(db => db.ListTrimAsync(key, start, stop, flags));
        }

        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public async Task<long> ListRightPushAsync<T>(string key, T value)
        {
            key = MergeKey(key);
            return await Do(db => db.ListRightPushAsync(key, ConvertJson(value)));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> ListRightPopAsync<T>(string key) where T : class
        {
            key = MergeKey(key);
            var value = await Do(db => db.ListRightPopAsync(key));
            return ConvertToObj<T>(value);
        }

        //public T ListRightPop<T>(string key) where T : class
        //{
        //    key = AddSysCustomKey(key);
        //    var value = Do(db => db.ListRightPop(key));
        //    return ConvertToObj<T>(value);
        //}

        /// <summary>
        /// 添加到头部
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public Task<long> ListLeftPushAsync<T>(string key, T value, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            if (value == null)
                return Task.FromResult((long)-1);
            key = MergeKey(key);
            return Do(db => db.ListLeftPushAsync(key, ConvertJson(value), when, flags));
        }

        public async Task<IEnumerable<T>> ListRangeAsync<T>(RedisKey key, long start = 0, long stop = -1, CommandFlags flags = CommandFlags.None) where T : class
        {
            key = MergeKey(key);
            return ConvetToList<T>(await Do(db => db.ListRangeAsync(key)));
        }

        /// <summary>
        /// 出栈,出队
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> ListLeftPopAsync<T>(string key) where T : class
        {
            key = MergeKey(key);
            var value = await Do(db => db.ListLeftPopAsync(key));
            return ConvertToObj<T>(value);
        }
        public T ListLeftPop<T>(string key) where T : class
        {
            key = MergeKey(key);
            var value = Do(db => db.ListLeftPop(key));
            return ConvertToObj<T>(value);
        }


        /// <summary>
        /// 获取集合中的数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<long> ListLengthAsync(string key)
        {
            key = MergeKey(key);
            return await Do(redis => redis.ListLengthAsync(key));
        }

        #endregion List

        #region SortedSet 有序集合

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="score"></param>
        public async Task<bool> SortedSetAddAsync<T>(string key, T value, double score, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson<T>(value), score, when, flags));
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public async Task<bool> SortedSetRemoveAsync<T>(string key, T value)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value)));
        }

        public Task<double> SortedSetIncrementAsync(string key, string member, double value, CommandFlags flags = CommandFlags.None)
        {
            key = MergeKey(key);
            return Do(redis => redis.SortedSetIncrementAsync(key, member, value, flags));
        }

        public Task<double> SortedSetDecrementAsync(string key, string member, double value)
        {
            key = MergeKey(key);
            return Do(redis => redis.SortedSetDecrementAsync(key, member, value));
        }


        /// <summary>
        /// 获取集合中的数量
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<long> SortedSetLengthAsync(string key)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SortedSetLengthAsync(key));
        }

        public async Task<long> SortedSetLengthByValueAsync(RedisKey key, RedisValue min, RedisValue max, Exclude exclude = Exclude.None)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SortedSetLengthByValueAsync(key, min, max, exclude));
        }

        public async Task<IEnumerable<T>> SortedSetRangeByRankAsync<T>(string key, long start = 0, long stop = -1, Order order = Order.Ascending) where T : class
        {
            key = MergeKey(key);
            var values = await Do(redis => redis.SortedSetRangeByRankAsync(key, start, stop, order));
            return ConvetToList<T>(values);
        }

        public async Task<SortedSetEntry[]> SortedSetRangeByRankWithScoresAsync(string key, long start = 0, long stop = -1, Order order = Order.Ascending)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SortedSetRangeByRankWithScoresAsync(key, start, stop, order));
        }

        public async Task<RedisValue[]> SortedSetRangeByScoreAsync(string key, long start, long stop, Exclude exclude = Exclude.None)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SortedSetRangeByScoreAsync(key, start, stop, exclude));
        }
        public async Task<SortedSetEntry[]> SortedSetRangeByScoreWithScoresAsync(string key, long start, long stop, Exclude exclude = Exclude.None)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SortedSetRangeByScoreWithScoresAsync(key, start, stop, exclude));
        }

        #endregion SortedSet 有序集合

        #region set集合

        public async Task<IEnumerable<T>> SetRandomMembersAsync<T>(RedisKey key, long count, CommandFlags flags = CommandFlags.None) where T : class
        {
            if (count <= 0)
                return Array.Empty<T>();
            key = MergeKey(key);
            return ConvetToList<T>(await Do(redis => redis.SetRandomMembersAsync(key, count, flags)));
        }
        public async Task<IEnumerable<T>> SetMembersAsync<T>(string key) where T : class
        {
            key = MergeKey(key);
            return ConvetToList<T>(await Do(db => db.SetMembersAsync(key)));
        }

        public async Task<long> SetLengthAsync(string key)
        {
            key = MergeKey(key);
            return await Do(db => db.SetLengthAsync(key));
        }

        public Task<bool> SetContainsAsync<T>(string key, T value)
        {
            key = MergeKey(key);
            return Do(redis => redis.SetContainsAsync(key, ConvertJson<T>(value)));
        }

        public Task<bool> SetAddAsync<T>(string key, T value, CommandFlags flags = CommandFlags.None)
        {
            key = MergeKey(key);
            return Do(redis => redis.SetAddAsync(key, ConvertJson<T>(value), flags));
        }

        public Task<bool> SetRemoveAsync<T>(string key, T value, CommandFlags flags = CommandFlags.None)
        {
            key = MergeKey(key);
            return Do(redis => redis.SetRemoveAsync(key, ConvertJson<T>(value), flags));
        }

        public async Task<T> SetPopAsync<T>(string key) where T : class
        {
            key = MergeKey(key);
            return ConvertToObj<T>(await Do(redis => redis.SetPopAsync(key)));
        }

        public async Task<string> SetRandomMemberAsync(string key)
        {
            key = MergeKey(key);
            return await Do(redis => redis.SetRandomMemberAsync(key));
        }

        #endregion

        #region key

        /// <summary>
		/// 搜索所有匹配关键字，*
		/// </summary>
		public async Task<IEnumerable<string>> SearchKeys(string pattern)
        {
            pattern = MergeKey(pattern);
            var keys = new HashSet<string>();
            int nextCursor = 0;
            do
            {
                RedisResult redisResult = await GetDatabase().ExecuteAsync("SCAN", nextCursor.ToString(), "MATCH", pattern, "COUNT", "1000");
                var innerResult = (RedisResult[])redisResult;
                nextCursor = int.Parse((string)innerResult[0]);
                var resultLines = (string[])innerResult[1];
                keys.UnionWith(resultLines);
            }
            while (nextCursor != 0);
            return keys;
        }

        public Task<long> KeyDeleteAsync(params string[] keys)
        {
            //keys.Select(it =>  (RedisKey)MergeKey(it));
            //keys = MergeKey(keys);
            return Do(db => db.KeyDeleteAsync(keys.Select(it => (RedisKey)MergeKey(it)).ToArray()));
        }

        /// <summary>
        /// 判断key是否存储
        /// </summary>
        /// <param name="key">redis key</param>
        /// <returns></returns>
        public bool KeyExists(string key)
        {
            key = MergeKey(key);
            return Do(db => db.KeyExists(key));
        }

        /// <summary>
        /// 重新命名key
        /// </summary>
        /// <param name="key">就的redis key</param>
        /// <param name="newKey">新的redis key</param>
        /// <returns></returns>
        public bool KeyRename(string key, string newKey)
        {
            key = MergeKey(key);
            return Do(db => db.KeyRename(key, newKey));
        }

        /// <summary>
        /// 设置Key的时间
        /// </summary>
        /// <param name="key">redis key</param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public bool KeyExpire(string key, TimeSpan? expiry = default(TimeSpan?))
        {
            key = MergeKey(key);
            return Do(db => db.KeyExpire(key, expiry));
        }

        #endregion key

        #region 发布订阅

        /// <summary>
        /// Redis发布订阅  订阅
        /// </summary>
        /// <param name="subChannel"></param>
        /// <param name="handler"></param>
        public void Subscribe(string subChannel, Action<RedisChannel, RedisValue> handler = null)
        {
            ISubscriber sub = ConnectionMultiplexer.GetSubscriber();
            sub.Subscribe(subChannel, (channel, message) =>
            {
                if (handler == null)
                {
                    Console.WriteLine(subChannel + " 订阅收到消息：" + message);
                }
                else
                {
                    handler(channel, message);
                }
            });
        }

        /// <summary>
        /// Redis发布订阅  发布
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="channel"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public long Publish<T>(string channel, T msg)
        {
            ISubscriber sub = ConnectionMultiplexer.GetSubscriber();
            return sub.Publish(channel, ConvertJson(msg));
        }

        /// <summary>
        /// Redis发布订阅  取消订阅
        /// </summary>
        /// <param name="channel"></param>
        public void Unsubscribe(string channel)
        {
            ISubscriber sub = ConnectionMultiplexer.GetSubscriber();
            sub.Unsubscribe(channel);
        }

        /// <summary>
        /// Redis发布订阅  取消全部订阅
        /// </summary>
        public void UnsubscribeAll()
        {
            ISubscriber sub = ConnectionMultiplexer.GetSubscriber();
            sub.UnsubscribeAll();
        }

        #endregion 发布订阅

        #region 锁
        public bool LockTake(string key, string value, TimeSpan? expiry = null)
        {
            //if (db.LockTake(GetKey("Locker"), token, TimeSpan.FromSeconds(10)))
            //{
            //    try
            //    {
            //        // you have the lock do work
            //    }
            //    finally
            //    {
            //        db.LockRelease(GetKey("Locker"), token);
            //    }
            //}
            return Do(redis => redis.LockTake(key, value, expiry ?? TimeSpan.FromSeconds(10)));
        }

        public Task<bool> LockReleaseAsync(string key, string value)
        {
            return Do(redis => redis.LockReleaseAsync(key, value));
        }

        #endregion

        #region 其他

        public ITransaction CreateTransaction()
        {
            return GetDatabase().CreateTransaction();
        }

        public IDatabase GetDatabase() => ConnectionMultiplexer.GetDatabase(DbNum);

        public IServer GetServer(string hostAndPort) => ConnectionMultiplexer.GetServer(hostAndPort);

        #endregion 其他

        #region 辅助方法

        private string MergeKey(string oldKey)
        {
            return CustomKey + oldKey;
        }


        private T Do<T>(Func<IDatabase, T> func)
        {
            var database = ConnectionMultiplexer.GetDatabase(DbNum);
            return func(database);
        }

        public T Do<T>(Func<IDatabase, string, T> func, string key)
        {
            key = MergeKey(key);
            var database = ConnectionMultiplexer.GetDatabase(DbNum);
            return func(database, key);
        }

        private string ConvertJson<T>(T value)
        {
            if (value == null)
                return null;
            string result = value is string ? value.ToString() : value.ToJsonString();
            //string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value);
            return result;
        }

        private T ConvertToObj<T>(RedisValue value) where T : class
        {
            if (value.HasValue)
                return typeof(T).Name == typeof(string).Name ? value.ToString() as T : JsonHelper.Deserialize<T>(value);
            else
                return default(T);
        }

        private IEnumerable<T> ConvetToList<T>(RedisValue[] values) where T : class
        {
            return values?.Select(it => ConvertToObj<T>(it));
        }

        private Dictionary<string, T> ConvetToDictionary<T>(HashEntry[] values) where T : class
        {
            if (values == null || values.Length == 0)
                return null;
            Dictionary<string, T> result = new Dictionary<string, T>();
            foreach (var item in values)
            {
                var model = ConvertToObj<T>(item.Value);
                result.Add(item.Name, model);
            }
            return result;
        }

        private RedisKey[] ConvertRedisKeys(List<string> redisKeys)
        {
            return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray();
        }

        #endregion 辅助方法


    }
}